源码学习:Menu组件顶部折叠样式优化
当菜单折叠时,Element Plus 的默认行为是将所有文字隐藏,只保留图标。但在顶部菜单(mode="horizontal")场景下,折叠后的样式可能不够理想——图标间距过大、hover 区域不精确、子菜单弹出位置偏移。本节通过阅读 Element Plus Menu 组件的源码,找到问题根因并实现定制化的样式优化。
Element Plus Menu 源码结构
Element Plus 的 Menu 组件源码位于 packages/components/menu/ 目录下:
menu/
├── src/
│ ├── menu.ts # el-menu 主组件
│ ├── menu-item.ts # el-menu-item
│ ├── sub-menu.ts # el-sub-menu
│ ├── use-menu.ts # 核心逻辑 composable
│ └── utils.ts # 工具函数
├── style/
│ ├── css.ts # CSS 导入入口
│ └── index.ts # 样式定义
└── index.ts # 导出入口
text
关键发现:use-menu.ts 中的 collapse 状态管理使用了 provide/inject,这意味着子组件(MenuItem、SubMenu)通过 inject 获取折叠状态,而非通过 props 逐层传递。
折叠样式的 CSS 分析
Element Plus 折叠时的核心 CSS:
.el-menu--collapse .el-menu-item,
.el-menu--collapse .el-sub-menu__title {
padding: 0 20px;
text-align: center;
}
.el-menu--collapse .el-menu-item [class^="el-icon"],
.el-menu--collapse .el-sub-menu__title [class^="el-icon"] {
margin-right: 0;
}
.el-menu--collapse .el-menu-item span,
.el-menu--collapse .el-sub-menu__title span {
display: none;
/* 隐藏文字 */
}
css
顶部折叠的样式问题
在 mode="horizontal" 下,折叠后可能出现:
- 图标间距过大:水平排列时
padding: 0 20px太宽。 - 子菜单弹出位置偏移:折叠状态下
el-sub-menu的弹出定位基于图标位置计算。 - Tooltip 显示异常:Element Plus 折叠时会给菜单项添加 Tooltip,但顶部菜单不需要。
自定义覆盖方案
// 覆盖顶部菜单折叠样式
.horizontal-collapse {
:deep(.el-menu--horizontal.el-menu--collapse) {
.el-menu-item,
.el-sub-menu__title {
padding: 0 12px; // 减小间距
}
}
}
scss
禁用折叠模式的 Tooltip
折叠模式下 Element Plus 自动为菜单项添加 Tooltip。如果不需要,可以通过 CSS 隐藏:
:deep(.el-menu--collapse .el-menu-item .el-tooltip__trigger) {
.el-tooltip {
display: none;
}
}
scss
或者通过覆盖 el-menu 的 ellipsis 属性来禁用:
<Menu :ellipsis="false" />
typescript
源码学习的收获
通过阅读 Element Plus 源码,可以学到:
- 状态管理:Menu 使用
provide/inject管理折叠状态,子组件通过inject获取,这是一种优雅的跨层级通信方式。 - CSS 组织:样式按功能拆分(基础样式、折叠样式、水平模式样式),便于理解。
- 边界处理:源码中大量使用
computed和watch处理边界情况(如折叠模式下的 Tooltip、嵌套子菜单的展开逻辑)。
本节小结
- 源码阅读:通过阅读 Element Plus Menu 源码,理解折叠状态的内部实现机制。
- CSS 覆盖:使用
:deep()选择器覆盖折叠模式下的默认样式。 - 间距优化:减小折叠状态下的
padding,使顶部菜单的图标排列更紧凑。
↑